package ginplus

import (
	"gitee.com/hongzhaomin/hzm-common-go/concurrent"
	"gitee.com/hongzhaomin/hzm-common-go/easylog"
	"time"
)

type HttpSession interface {
	GetAttribute(key string) any

	SetAttribute(key string, value any)

	RemoveAttribute(key string)

	SetSurvivalTime(mills int64)
}

func NewDefaultHttpSession(logger easylog.Logger) *DefaultHttpSession {
	return &DefaultHttpSession{
		logger:        logger,
		attributesMap: concurrent.NewMap[string, *attribute](),
		survivalTime:  time.Hour.Milliseconds() * 8,
	}
}

var _ HttpSession = (*DefaultHttpSession)(nil)

type DefaultHttpSession struct {
	logger        easylog.Logger
	attributesMap *concurrent.Map[string, *attribute]
	survivalTime  int64 // 存活时间（毫秒时间戳）
}

type attribute struct {
	createTime int64 // 创建时间（毫秒时间戳）
	key        string
	value      any
}

func (my *DefaultHttpSession) init() {
	ticker := time.NewTicker(24 * time.Hour)
	go my.cleanSessionTask(ticker)
}

func (my *DefaultHttpSession) cleanSessionTask(t *time.Ticker) {
	for {
		select {
		case <-t.C:
			expiredKeys := make([]string, 0)
			my.attributesMap.Range(func(key string, attr *attribute) bool {
				if my.attrExpired(attr) {
					expiredKeys = append(expiredKeys, key)
				}
				return true
			})
			for _, key := range expiredKeys {
				my.logger.Info("key [%s] 已过期，即将删除", key)
				my.RemoveAttribute(key)
			}
		}
	}
}

func (my *DefaultHttpSession) SetAttribute(key string, value any) {
	my.attributesMap.Store(key, &attribute{
		createTime: time.Now().UnixMilli(),
		key:        key,
		value:      value,
	})
}

func (my *DefaultHttpSession) GetAttribute(key string) any {
	attr, ok := my.attributesMap.Load(key)
	if !ok {
		return nil
	}
	// 过期则懒删除
	if attr == nil || my.attrExpired(attr) {
		my.RemoveAttribute(key)
		return nil
	}
	return attr.value
}

func (my *DefaultHttpSession) RemoveAttribute(key string) {
	my.attributesMap.Delete(key)
}

func (my *DefaultHttpSession) SetSurvivalTime(mills int64) {
	my.survivalTime = mills
}

func (my *DefaultHttpSession) attrExpired(attr *attribute) bool {
	return attr.createTime+my.survivalTime < time.Now().UnixMilli()
}
